package com.sharing.backgroundmodule.service;

import com.sharing.backgroundmodule.dto.UserProductionHobby;
import com.sharing.backgroundmodule.mapper.BackstageUserHobbyMapper;
import com.sharing.common.Page;
import com.sharing.common.Result;
import com.sharing.domain.*;
import com.sharing.domain.dto.UserDto;
import com.sharing.mapper.HobbyMapper;
import com.sharing.mapper.UserMapper;
import com.sharing.service.BrowseRecordService;
import com.sharing.util.LRUCache;
import com.sharing.util.ThreadLocalStorage;
import lombok.extern.slf4j.Slf4j;
import org.quartz.ee.jta.UserTransactionHelper;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.*;

/**
 * @author MingTian
 * @version 1.0
 * @description TODO
 * @date 2023/4/3 10:39
 */
@Slf4j
@Service
public class BackstageUserHobbyService {
    @Autowired
    private BackstageUserHobbyMapper userHobbyMapper;

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private HobbyMapper hobbyMapper;

    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Autowired
    private BrowseRecordService browseRecordService;

    /**
     * 根据用户Id查询该用户所有的后台兴趣
     * @param userId
     * @return
     */
    public Result<List<UserHobby>> selectHobbyByUserId(Integer userId) {
        if (userId == null) {
            return new Result<>(1, "参数不能为空");
        }

        List<UserHobby> userHobbies = userHobbyMapper.selectUserHobbyByUserId(userId);

        return new Result<>(0, userHobbies);
    }

    /**
     * 根据用户Id查询用户兴趣的业务层方法
     * @param userId
     * @param level
     * @param page
     * @param size
     * @return
     */
    public Result<Page<Hobby>> selectHobbyByUserId(Integer userId, Integer level, Integer page, Integer size) {
        // 校验参数
        if (userId == null || page == null || size == null) {
            return new Result<>(1, "参数不当");
        }

        // 获取当前登录用户
        User loginUser = ThreadLocalStorage.getUser();
        if (loginUser == null) {
            synchronized (this) {
                if (loginUser == null) {
                    Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
                    loginUser = userMapper.selectUserByUserName(authentication.getName());
                    ThreadLocalStorage.setUser(loginUser);
                }
            }
        }

        // 若当前登录用户不是所查询的用户兴趣信息
        if (!Objects.equals(loginUser.getId(), userId)) {
            if (!loginUser.getIdentity().equals("管理用户")) {
                return new Result<>(1, "您没有权限，请获取管理员权限或者查询当前用户的兴趣信息");
            }
        }

        // 获取所要查询的用户
        User user = userMapper.selectUserById(userId);
        if (user == null) {
            return new Result<>(1, "该用户不存在");
        }

        // 查询兴趣的总数
        Integer total = userHobbyMapper.selectHobbyNumByUserId(userId, level);

        // 查询用户的兴趣ids
        List<Integer> ids = userHobbyMapper.selectHobbyIdsByUserId(userId, level, (page - 1) * size, size);

        if (ids.size() == 0) {
            return new Result<>(1, "未添加兴趣");
        }

        // 通过ids从兴趣表查询详细信息
        List<Hobby> hobbies = hobbyMapper.selectHobbyByIds(ids);

        return new Result<>(0, new Page<>(total, size, hobbies));
    }

    /**
     * 根据兴趣查询用户基本信息的业务层方法
     * @param hobbies
     * @param page
     * @param size
     * @return
     */
    public Result<Page<UserDto>> selectUsersByHobby(List<String> hobbies, Integer page, Integer size) {
        // 校验参数一：
        if (hobbies == null || hobbies.size() == 0) {
            return new Result<>(1, "请至少传入一个兴趣");
        }

        // 校验参数二：
        if (page == null || size == null) {
            return new Result<>(1, "参数不当");
        }

        // 获取兴趣的ids
        List<Integer> hobbyIds = hobbyMapper.selectHobbyIdsByHobby(hobbies);

        // 查询总数
        Integer total = userHobbyMapper.selectUserDtosNumByHobbyIds(hobbyIds);

        // 通过兴趣ids获取对应用户以及每个用户满足的兴趣次数
        List<UserDto> userDtos = userHobbyMapper.selectUserDtosByHobbyIds(hobbyIds, (page - 1) * size, size);

        return new Result<>(0, new Page<>(total, size, userDtos));
    }

    /**
     * 新增用户兴趣的业务层方法————单个
     * @param userHobby
     * @return
     */
    public Result<UserHobby> insertHobby(UserHobby userHobby) {
        // 校验参数的合法性
        if (userHobby == null || userHobby.getHobbyId() == null || userHobby.getUserId() == null) {
            return new Result(1, "参数传入不当");
        }

        // 校验该用户是否已经存在
        User user = userMapper.selectUserById(userHobby.getUserId());
        if (user == null) {
            return new Result(1, "该用户不存在");
        }

        // 查询该用户已有的兴趣
        List<Hobby> hobbies = userHobbyMapper.selectHobbyByUserId(userHobby.getUserId());
        for (Hobby hobby : hobbies) {
            if (Objects.equals(hobby.getId(), userHobby.getHobbyId())) {
                return new Result(1, "该兴趣已存在，无需添加");
            }
        }

        Integer rows = userHobbyMapper.insertHobby(userHobby);

        if (rows != 1) {
            return new Result<>(1, "新增失败");
        }

        return new Result<>(0, userHobby);
    }

    /**
     * 新增用户兴趣的业务层方法————多个
     * @param userHobbies
     * @return
     */
    public Result<Integer> insertHobbies(List<UserHobby> userHobbies) {
        // 校验参数
        if (userHobbies == null || userHobbies.size() == 0) {
            return new Result<>(1, "传入参数不当");
        }

        StringBuffer message = new StringBuffer();
        Set<String> strings = new HashSet<>();
        int rows = 0;
        for (int i = 0; i < userHobbies.size(); i++) {
            Result<UserHobby> result = insertHobby(userHobbies.get(i));
            if (result.getState() == 0) {
                rows++;
            } else {
                strings.add(result.getMessage() + "\n");
            }
        }

        // 获取新增的用户兴趣中的所有用户
        Set<Integer> userIds = new HashSet<>();
        for (int i = 0; i < userHobbies.size(); i++) {
            userIds.add(userHobbies.get(i).getUserId());
        }

        // 判断新增兴趣的用户的兴趣是否已经过界
        for (int userId : userIds) {
            boolean isOut = checkHobbyAmountOutOfBounds(userId);

            if (isOut) {
                // 若已经过界，交由 rabbitmq 队列存储
                rabbitTemplate.convertAndSend("X", "XA", "用户ID: " + userId + " 的用户的兴趣数量过界");
            }
        }

        // 若全部新增成功
        if (rows == userHobbies.size()) {
            return new Result<>(0, rows);
        }

        // 若存在没有新增成功的，那么需要封装并反馈可能失败的原因
        message.append(userHobbies.size() - rows)
                .append("个兴趣添加失败")
                .append("\n 可能的原因如下：\n");
        for (String str : strings) {
            message.append(str);
        }
        return new Result<>(1, message.toString());
    }

    /**
     * 判断用户的兴趣数量是否已经过界
     * 默认最多为 5个
     * @param userId
     * @return
     */
    private boolean checkHobbyAmountOutOfBounds(Integer userId) {
        Integer total = userHobbyMapper.selectHobbyNumberByUserId(userId);

        if (total <= 5) return false;
        return true;
    }

    /**
     * 删除用户兴趣的业务层方法————多个
     * @param hobbyIds
     * @param userId
     * @return
     */
    public Result<Integer> deleteHobbies(List<Integer> hobbyIds, Integer userId) {
        // 校验参数
        if (hobbyIds == null || hobbyIds.size() == 0 || userId == null) {
            return new Result<>(1, "参数不当");
        }

        // 获取当前登录用户
        User loginUser = ThreadLocalStorage.getUser();
        if (loginUser == null) {
            synchronized (this) {
                if (loginUser == null) {
                    Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
                    loginUser = userMapper.selectUserByUserName(authentication.getName());
                    ThreadLocalStorage.setUser(loginUser);
                }
            }
        }

        // 若当前登录用户不是所修改的用户兴趣信息
        if (!Objects.equals(loginUser.getId(), userId)) {
            if (!loginUser.getIdentity().equals("管理用户")) {
                return new Result<>(1, "您没有权限删除该用户的兴趣，除非您获得‘管理用户’的权限或者仅仅删除您当前的兴趣");
            }
        }

        // 若当前登录用户就是所修改的用户或当前用户是管理用户
        Integer rows = userHobbyMapper.deleteHobbyByUserIdAndHobbyIds(hobbyIds, userId);

        if (rows == hobbyIds.size()) {
            return new Result<>(0, rows);
        }
        return new Result<>(1, (hobbyIds.size() - rows) + "个兴趣删除失败");
    }

    /**
     * 删除该用户兴趣数量过界问题
     * 基于 LRU 算法实现
     * @param userId
     */
    public void dealHobbyAmountOutOfBoundsLRU(Integer userId) {
        // 查询该用户在后台用户兴趣表中最早的兴趣添加日期
        String begin = userHobbyMapper.selectEarlyDate(userId);

        // 查询该用户在某个日期范围内的浏览记录
        List<UserProductionHobby> userProductionHobbies = browseRecordService.selectUserProductionHobbyByUserIdAndBeginDate(userId, begin);

        // 创建 LRUCache，通过 LRU 算法进行选择仍然可以留下的兴趣
        LRUCache lruCache = new LRUCache(5);

        for (int i = 0; i < userProductionHobbies.size(); i++) {
            lruCache.put(userProductionHobbies.get(i).getHobbyId(), 0);
        }

        // 通过上述的 LRUCache 数据结构不断地调用 put 函数，
        // 目前该数据结构中留存的五个兴趣是需要继续保留的，
        // 其余的兴趣应该删除

        // 查询在后台中该用户所有的兴趣
        List<UserHobby> userHobbies = selectHobbyByUserId(userId).getData();

        // 需要删除的兴趣，可能不止一个
        List<Integer> hobbyIds = new ArrayList<>();

        for (int i = 0; i < userHobbies.size(); i++) {
            if (lruCache.get(userHobbies.get(i).getHobbyId()) == 0) {
                // 表明 LRUCache 中保留了该兴趣
                continue;
            } else {
                // 需要删除的兴趣
                hobbyIds.add(userHobbies.get(i).getHobbyId());
            }
        }

        // 调用删除兴趣的方法，进行删除逻辑
        deleteHobbies(hobbyIds, userId);
    }

    /**
     * 删除该用户兴趣数量过界问题
     * 基于 FIFO先进先出 算法实现
     * @param userId
     */
    public void dealHobbyAmountOutOfBoundsFIFO(Integer userId) {
        // 查询该用户后台兴趣表中最早几个（超出兴趣数量上界）的兴趣
        List<UserHobby> userHobbies = selectFirstUserHobbyByUserId(userId);
    }

    /**
     * 查询该用户后台兴趣表中最早几个（超出兴趣数量上界）的兴趣
     * @param userId
     * @return
     */
    private List<UserHobby> selectFirstUserHobbyByUserId(Integer userId) {
        // 查询该用户兴趣数量
        Integer nums = selectHobbyNumbersByUserId(userId);

        // 数据库查询需要被删除的兴趣
        List<UserHobby> userHobbies = userHobbyMapper.selectFirstUserHobbyByUserId(userId, nums - 5);

        // 准备删除方法的参数
        List<Integer> hobbyIds = new ArrayList<>();
        for (int i = 0; i < userHobbies.size(); i++) {
            hobbyIds.add(userHobbies.get(i).getHobbyId());
        }

        // 执行删除业务逻辑
        deleteHobbies(hobbyIds, userId);

        return userHobbies;
    }

    /**
     * 查询该用户兴趣数量
     * @param userId
     * @return
     */
    private Integer selectHobbyNumbersByUserId(Integer userId) {
        Integer nums = userHobbyMapper.selectHobbyNumbersByUserId(userId);

        return nums;
    }
}
